/**
 * Copyright 2009 Erick Armbrust 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 *   
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */

package tapioca.dt;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Transaction;

import tapioca.dt.WrappedDatastoreService.GetResponse;
import tapioca.testing.AppEngineTestCase;

/**
 * Tests for the {@link WrappedDatastoreService} class.
 *
 * @author armbrust@gmail.com (Erick Armbrust)
 */
public class WrappedDatastoreServiceTest extends AppEngineTestCase {

  private WrappedDatastoreService dts;
  
  @Override
  public void setUp() throws Exception {
    super.setUp();
    dts = new WrappedDatastoreService(ds);
  }
  
  @Override
  public void tearDown() throws Exception {
    for (Transaction txn : ds.getActiveTransactions()) {
      txn.rollback();
    }
    dts = null;
    super.tearDown();
  }
  
  public void testGetNonNamedEntity() {
    Entity f1 = createAndSaveDtEntity("foo", "bar");
    GetResponse response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
  }
  
  public void testGetNamedEntity() {
    Entity f1 = createAndSaveDtNamedEntity("foo", "bar", "dt__baz");
    GetResponse response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
  }
  
  public void testGetNonExistantNonNamedEntity() {
    Key key = KeyFactory.createKey("foo", 1L);
    GetResponse response = dts.get(key);
    assertNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertNull(response.getVersion());
  }
  
  public void testGetNonExistantNamedEntity() {
    Key key = KeyFactory.createKey("foo", "dt__bar");
    GetResponse response = dts.get(key);
    assertNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertNull(response.getVersion());
    
    Entity f1 = createAndSaveDtNamedEntity("foo", "bar", "dt__baz");
    ds.delete(f1.getKey());
    
    response = dts.get(f1.getKey());
    assertNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());    
  }  
  
  public void testGetValidation() throws Exception {
    Entity notDtCapable = new Entity("foo");
    ds.put(notDtCapable);
    try {
      dts.get(notDtCapable.getKey());
      fail("This should fail as being a non-DT capable entity.");
    } catch (IllegalArgumentException e) {
      // Good.
    }
    
    notDtCapable = new Entity("foo", "bar");
    ds.put(notDtCapable);
    try {
      dts.get(notDtCapable.getKey());
      fail("This should fail since there is no corresponding metadata entity.");
    } catch (IllegalStateException e) {
      // Good.
    }    
    
    Entity incompletePmd = new Entity(WrappedDatastoreService.PMD_KIND, WrappedDatastoreService.PMD_KEY_NAME, 
        notDtCapable.getKey());
    /*Transaction txn = ds.beginTransaction();
    ds.put(txn, incompletePmd);
    txn.commit();*/
    ds.put(incompletePmd);
    
    try {
      dts.get(notDtCapable.getKey());
      fail("This should fail since the metadata object is incomplete.");
    } catch (IllegalArgumentException e) {
      // Good.
    }     
  }
  
  public void testPutNonNamedEntity() {
    Entity f1 = createAndSaveDtEntity("foo", "bar");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNotNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
    
    Transaction txn = ds.beginTransaction();
    dts.put(txn, f1, dtKey);
    txn.commit();
    
    response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dtKey, response.getVersion());
  }
  
  public void testPutNamedEntity() {
    Entity f1 = createAndSaveDtNamedEntity("foo", "bar", "dt__baz");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNotNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
    
    Transaction txn = ds.beginTransaction();
    dts.put(txn, f1, dtKey);
    txn.commit();
    
    response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dtKey, response.getVersion());        
  }
  
  public void testDeleteNonNamedEntity() {
    Entity f1 = createAndSaveDtEntity("foo", "bar");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNotNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
    
    Transaction txn = ds.beginTransaction();
    dts.delete(txn, f1.getKey(), dtKey);
    txn.commit();
    
    response = dts.get(f1.getKey());
    assertNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertNull(response.getVersion());    
  }
  
  public void testDeleteNamedEntity() {
    Entity f1 = createAndSaveDtNamedEntity("foo", "bar", "dt__baz");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNotNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
    
    Transaction txn = ds.beginTransaction();
    dts.delete(txn, f1.getKey(), dtKey);
    txn.commit();
    
    response = dts.get(f1.getKey());
    assertNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertNull(response.getWriteLock());
    assertEquals(dtKey, response.getVersion());          
  }  
  
  public void testSetAndSaveWriteLockForNonNamedEntity() {
    Entity f1 = createAndSaveDtEntity("foo", "bar");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());    
    
    Transaction txn = ds.beginTransaction();
    dts.setAndSaveWriteLock(txn, response, dtKey);
    txn.commit();
    
    response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNull(response.getPureMetaData());
    assertEquals(dtKey, response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());
  }
  
  public void testSetAndSaveWriteLockForNamedEntity() {
    Entity f1 = createAndSaveDtNamedEntity("foo", "bar", "dt__baz");
    Key dtKey = KeyFactory.createKey(DistributedTransactionEntity.KIND, 1L);
    GetResponse response = dts.get(f1.getKey());
    
    assertNull(response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());    
    
    Transaction txn = ds.beginTransaction();
    dts.setAndSaveWriteLock(txn, response, dtKey);
    txn.commit();
        
    response = dts.get(f1.getKey());
    assertNotNull(response.getEntity());
    assertNotNull(response.getPureMetaData());
    assertEquals(dtKey, response.getWriteLock());
    assertEquals(dummyVersion, response.getVersion());    
  }  
  
}
